package com.piece.core.framework.util.string;

import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.collection.ArrayUtil;
import com.piece.core.framework.util.math.DigestUtil;
import com.piece.core.framework.util.object.ClassUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrBuilder;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.*;
import java.security.MessageDigest;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang3.StringEscapeUtils.UNESCAPE_HTML4;
import static org.apache.commons.lang3.StringEscapeUtils.UNESCAPE_JAVA;

/**
 * 字符串工具类
 */
@Slf4j
public class StringUtil extends org.apache.commons.lang3.StringUtils {

    /**
     * 空字符串
     */
    private static final String EMPTY_STRING = "";

    /**
     * 下划线
     */
    private static final String SEPARATOR = "_";

    /**
     * 占位符
     */
    public static final String EMPTY_JSON = "{}";

    /**
     * 转义符
     */
    public static final char C_BACKSLASH = '\\';

    /**
     * 占位符-起始
     */
    public static final char C_DELIM_START = '{';

    /**
     * 数字字符串
     */
    public static final String NUMBER_CHAR = "0123456789";

    public static boolean equals(CharSequence str1, CharSequence str2) {
        return equals(str1, str2, false);
    }

    public static boolean equalsIgnoreCase(CharSequence str1, CharSequence str2) {
        return equals(str1, str2, true);
    }

    public static boolean equals(CharSequence str1, CharSequence str2, boolean ignoreCase) {
        if (null == str1) {
            return str2 == null;
        } else if (null == str2) {
            return false;
        } else {
            return ignoreCase ? str1.toString().equalsIgnoreCase(str2.toString()) : str1.toString().contentEquals(str2);
        }
    }

    public static boolean equalsAnyIgnoreCase(CharSequence str1, CharSequence... strs) {
        return equalsAny(str1, true, strs);
    }

    public static boolean equalsAny(CharSequence str1, CharSequence... strs) {
        return equalsAny(str1, false, strs);
    }

    public static boolean equalsAny(CharSequence str1, boolean ignoreCase, CharSequence... strs) {
        if (!ArrayUtil.isEmpty(strs)) {
            CharSequence[] var3 = strs;
            int var4 = strs.length;

            for (int var5 = 0; var5 < var4; ++var5) {
                CharSequence str = var3[var5];
                if (equals(str1, str, ignoreCase)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean equalsCharAt(CharSequence str, int position, char c) {
        if (null != str && position >= 0) {
            return str.length() > position && c == str.charAt(position);
        } else {
            return false;
        }
    }

    public static boolean isSubEquals(CharSequence str1, int start1, CharSequence str2, int start2, int length, boolean ignoreCase) {
        return null != str1 && null != str2 ? str1.toString().regionMatches(ignoreCase, start1, str2.toString(), start2, length) : false;
    }

    public static boolean isEmpty(CharSequence cs) {
        if (null == cs || cs.length() == 0) {
            return true;
        }

        if ("null".equalsIgnoreCase(cs.toString())
            || "undefined".equalsIgnoreCase(cs.toString())) {
            return true;
        }

        return false;
    }

    public static boolean isBlankChar(char c) {
        return isBlankChar((int)c);
    }

    public static boolean isBlankChar(int c) {
        return Character.isWhitespace(c) || Character.isSpaceChar(c) || c == 65279 || c == 8234 || c == 0;
    }

    public static String trim(CharSequence str) {
        return null == str ? null : trim(str, 0);
    }

    public static String trimToEmpty(CharSequence str) {
        return null == str ? "" : trim(str);
    }

    public static String trimToNull(CharSequence str) {
        String trimStr = trim(str);
        return "".equals(trimStr) ? null : trimStr;
    }

    public static String trimStart(CharSequence str) {
        return trim(str, -1);
    }

    public static String trimEnd(CharSequence str) {
        return trim(str, 1);
    }

    public static String trim(CharSequence str, int mode) {
        String result;
        if (null == str) {
            result = null;
        } else {
            int length = str.length();
            int start = 0;
            int end = length;
            if (mode <= 0) {
                while(start < end && isBlankChar(str.charAt(start))) {
                    ++start;
                }
            }

            if (mode >= 0) {
                while(start < end && isBlankChar(str.charAt(end - 1))) {
                    --end;
                }
            }

            if (start <= 0 && end >= length) {
                result = str.toString();
            } else {
                result = str.toString().substring(start, end);
            }
        }

        return result;
    }

    public static boolean startWith(CharSequence str, char c) {
        if (isEmpty(str)) {
            return false;
        } else {
            return c == str.charAt(0);
        }
    }

    public static boolean startWith(CharSequence str, CharSequence prefix, boolean ignoreCase) {
        return startWith(str, prefix, ignoreCase, false);
    }

    public static boolean startWith(CharSequence str, CharSequence prefix, boolean ignoreCase, boolean ignoreEquals) {
        if (null != str && null != prefix) {
            boolean isStartWith;
            if (ignoreCase) {
                isStartWith = str.toString().toLowerCase().startsWith(prefix.toString().toLowerCase());
            } else {
                isStartWith = str.toString().startsWith(prefix.toString());
            }

            if (!isStartWith) {
                return false;
            } else {
                return !ignoreEquals || !equals(str, prefix, ignoreCase);
            }
        } else if (!ignoreEquals) {
            return false;
        } else {
            return null == str && null == prefix;
        }
    }

    public static boolean startWith(CharSequence str, CharSequence prefix) {
        return startWith(str, prefix, false);
    }

    public static boolean startWithIgnoreEquals(CharSequence str, CharSequence prefix) {
        return startWith(str, prefix, false, true);
    }

    public static boolean startWithIgnoreCase(CharSequence str, CharSequence prefix) {
        return startWith(str, prefix, true);
    }

    public static boolean startWithAny(CharSequence str, CharSequence... prefixes) {
        if (!isEmpty(str) && !ArrayUtil.isEmpty(prefixes)) {
            CharSequence[] var2 = prefixes;
            int var3 = prefixes.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                CharSequence suffix = var2[var4];
                if (startWith(str, suffix, false)) {
                    return true;
                }
            }

            return false;
        } else {
            return false;
        }
    }

    public static boolean endWith(CharSequence str, char c) {
        if (isEmpty(str)) {
            return false;
        } else {
            return c == str.charAt(str.length() - 1);
        }
    }

    public static boolean endWith(CharSequence str, CharSequence suffix, boolean isIgnoreCase) {
        if (null != str && null != suffix) {
            return isIgnoreCase ? str.toString().toLowerCase().endsWith(suffix.toString().toLowerCase()) : str.toString().endsWith(suffix.toString());
        } else {
            return null == str && null == suffix;
        }
    }

    public static boolean endWith(CharSequence str, CharSequence suffix) {
        return endWith(str, suffix, false);
    }

    public static boolean endWithIgnoreCase(CharSequence str, CharSequence suffix) {
        return endWith(str, suffix, true);
    }

    public static boolean endWithAny(CharSequence str, CharSequence... suffixes) {
        if (!isEmpty(str) && !ArrayUtil.isEmpty(suffixes)) {
            CharSequence[] var2 = suffixes;
            int var3 = suffixes.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                CharSequence suffix = var2[var4];
                if (endWith(str, suffix, false)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean endWithAnyIgnoreCase(CharSequence str, CharSequence... suffixes) {
        if (!isEmpty(str) && !ArrayUtil.isEmpty(suffixes)) {
            CharSequence[] var2 = suffixes;
            int var3 = suffixes.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                CharSequence suffix = var2[var4];
                if (endWith(str, suffix, true)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean contains(CharSequence str, char searchChar) {
        return indexOf(str, searchChar) > -1;
    }

    public static boolean contains(CharSequence str, CharSequence searchStr) {
        return null != str && null != searchStr ? str.toString().contains(searchStr) : false;
    }

    public static boolean containsAny(CharSequence str, CharSequence... strs) {
        return null != getContainsStr(str, strs);
    }

    public static boolean containsAny(CharSequence str, char... chars) {
        if (!isEmpty(str)) {
            int len = str.length();

            for(int i = 0; i < len; ++i) {
                if (ArrayUtil.contains(chars, str.charAt(i))) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean containsOnly(CharSequence str, char... chars) {
        if (!isEmpty(str)) {
            int len = str.length();

            for(int i = 0; i < len; ++i) {
                if (!ArrayUtil.contains(chars, str.charAt(i))) {
                    return false;
                }
            }
        }
        return true;
    }

    public static boolean containsBlank(CharSequence str) {
        if (null != str) {
            int length = str.length();
            if (0 != length) {
                for (int i = 0; i < length; ++i) {
                    if (isBlankChar(str.charAt(i))) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public static boolean containsIgnoreCase(CharSequence str, CharSequence strs) {
        if (null == str) {
            return null == strs;
        } else {
            return str.toString().toLowerCase().contains(strs.toString().toLowerCase());
        }
    }

    public static boolean containsAnyIgnoreCase(CharSequence str, CharSequence... strs) {
        return null != getContainsStrIgnoreCase(str, strs);
    }

    public static String getContainsStrIgnoreCase(CharSequence str, CharSequence... strs) {
        if (!isEmpty(str) && !ArrayUtil.isEmpty(strs)) {
            CharSequence[] var2 = strs;
            int var3 = strs.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                CharSequence testStr = var2[var4];
                if (containsIgnoreCase(str, testStr)) {
                    return testStr.toString();
                }
            }
        }
        return null;
    }

    /**
     * 查找包含的第一个字符
     */
    public static String getContainsStr(CharSequence str, CharSequence... strs) {
        if (!isEmpty(str) && !ArrayUtil.isEmpty(strs)) {
            CharSequence[] var2 = strs;
            int var3 = strs.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                CharSequence checkStr = var2[var4];
                if (str.toString().contains(checkStr)) {
                    return checkStr.toString();
                }
            }
        }
        return null;
    }

    public static String addPrefixIfNot(CharSequence str, CharSequence prefix) {
        return prependIfMissing(str, prefix, prefix);
    }

    public static String addSuffixIfNot(CharSequence str, CharSequence suffix) {
        return appendIfMissing(str, suffix, suffix);
    }

    public static String appendIfMissing(CharSequence str, CharSequence suffix, CharSequence... suffixes) {
        return appendIfMissing(str, suffix, false, suffixes);
    }

    public static String appendIfMissingIgnoreCase(CharSequence str, CharSequence suffix, CharSequence... suffixes) {
        return appendIfMissing(str, suffix, true, suffixes);
    }

    public static String appendIfMissing(CharSequence str, CharSequence suffix, boolean ignoreCase, CharSequence... testSuffixes) {
        if (null != str && !isEmpty(suffix) && !endWith(str, suffix, ignoreCase)) {
            if (ArrayUtil.isNotEmpty(testSuffixes)) {
                CharSequence[] var4 = testSuffixes;
                int var5 = testSuffixes.length;

                for(int var6 = 0; var6 < var5; ++var6) {
                    CharSequence testSuffix = var4[var6];
                    if (endWith(str, testSuffix, ignoreCase)) {
                        return str.toString();
                    }
                }
            }

            return str.toString().concat(suffix.toString());
        } else {
            return null == str ? null : str.toString();
        }
    }

    public static String prependIfMissing(CharSequence str, CharSequence prefix, CharSequence... prefixes) {
        return prependIfMissing(str, prefix, false, prefixes);
    }

    public static String prependIfMissingIgnoreCase(CharSequence str, CharSequence prefix, CharSequence... prefixes) {
        return prependIfMissing(str, prefix, true, prefixes);
    }

    public static String prependIfMissing(CharSequence str, CharSequence prefix, boolean ignoreCase, CharSequence... prefixes) {
        if (null != str && !isEmpty(prefix) && !startWith(str, prefix, ignoreCase)) {
            if (null != prefixes && prefixes.length > 0) {
                CharSequence[] var4 = prefixes;
                int var5 = prefixes.length;

                for(int var6 = 0; var6 < var5; ++var6) {
                    CharSequence s = var4[var6];
                    if (startWith(str, s, ignoreCase)) {
                        return str.toString();
                    }
                }
            }

            return prefix.toString().concat(str.toString());
        } else {
            return null == str ? null : str.toString();
        }
    }

    public static String upperFirst(CharSequence str) {
        return changeFirst(str, true);
    }

    public static String lowerFirst(CharSequence str) {
        return changeFirst(str, false);
    }

    public static String changeFirst(CharSequence str, boolean upperCase) {
        if (null == str) {
            return null;
        } else {
            if (str.length() > 0) {
                char firstChar = str.charAt(0);
                if (upperCase && Character.isUpperCase(firstChar)) {
                    return Character.toLowerCase(firstChar) + substring(str.toString(), 1);
                } else if (!upperCase && Character.isLowerCase(firstChar)) {
                    return Character.toUpperCase(firstChar) + substring(str.toString(), 1);
                }
            }
            return str.toString();
        }
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @return 结果
     */
    public static String substring(final String str, int start) {
        if (null == str) {
            return EMPTY_STRING;
        }

        if (start < 0) {
            start = str.length() + start;
        }

        if (start < 0) {
            start = 0;
        }
        if (start > str.length()) {
            return EMPTY_STRING;
        }

        return str.substring(start);
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @param end   结束
     * @return 结果
     */
    public static String substring(final String str, int start, int end) {
        if (null == str) {
            return EMPTY_STRING;
        }

        if (end < 0) {
            end = str.length() + end;
        }
        if (start < 0) {
            start = str.length() + start;
        }

        if (end > str.length()) {
            end = str.length();
        }

        if (start > end) {
            return EMPTY_STRING;
        }

        if (start < 0) {
            start = 0;
        }
        if (end < 0) {
            end = 0;
        }

        return str.substring(start, end);
    }

    public static String subBefore(CharSequence string, CharSequence separator, boolean isLastSeparator) {
        if (!isEmpty(string) && separator != null) {
            String str = string.toString();
            String sep = separator.toString();
            if (sep.isEmpty()) {
                return "";
            } else {
                int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep);
                return subBefore(string, pos);
            }
        } else {
            return null == string ? null : string.toString();
        }
    }

    public static String subBefore(CharSequence string, char separator, boolean isLastSeparator) {
        if (isEmpty(string)) {
            return null == string ? null : "";
        } else {
            String str = string.toString();
            int pos = isLastSeparator ? str.lastIndexOf(separator) : str.indexOf(separator);
            return subBefore(string, pos);
        }
    }

    public static String subBefore(CharSequence string, int pos) {
        if (isEmpty(string)) {
            return null == string ? null : "";
        } else {
            String str = string.toString();
            if (-1 == pos) {
                return str;
            } else {
                return 0 == pos ? "" : str.substring(0, pos);
            }
        }
    }

    public static String subAfter(CharSequence string, CharSequence separator, boolean isLastSeparator) {
        if (isEmpty(string)) {
            return null == string ? null : "";
        } else if (null == separator) {
            return "";
        } else {
            String str = string.toString();
            String sep = separator.toString();
            int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep);
            return subAfter(str, pos, separator.length());
        }
    }

    public static String subAfter(CharSequence string, char separator, boolean isLastSeparator) {
        if (isEmpty(string)) {
            return null == string ? null : "";
        } else {
            String str = string.toString();
            int pos = isLastSeparator ? str.lastIndexOf(separator) : str.indexOf(separator);
            return subAfter(str, pos, 0);
        }
    }

    public static String subAfter(String string, int pos, int length) {
        if (isEmpty(string)) {
            return null == string ? null : "";
        } else {
            return -1 != pos && string.length() - 1 != pos ? string.substring(pos + length) : "";
        }
    }

    public static String subBetween(CharSequence str, CharSequence before, CharSequence after) {
        if (null != str && null != before && null != after) {
            String str2 = str.toString();
            String before2 = before.toString();
            String after2 = after.toString();
            int start = str2.indexOf(before2);
            if (start != -1) {
                int end = str2.indexOf(after2, start + before2.length());
                if (end != -1) {
                    return str2.substring(start + before2.length(), end);
                }
            }

        }
        return null;
    }

    public static String subBetween(CharSequence str, CharSequence beforeAndAfter) {
        return subBetween(str, beforeAndAfter, beforeAndAfter);
    }

    /**
     * 隐藏字符
     */
    public static String hide(CharSequence str, int startInclude, int endExclude) {
        return replace(str, startInclude, endExclude, '*');
    }

    public static String replace(CharSequence str, int startInclude, int endExclude, char replacedChar) {
        if (isEmpty(str)) {
            return null == str ? null : str.toString();
        } else {
            int strLength = str.length();
            if (startInclude > strLength) {
                return null == str ? null : str.toString();
            } else {
                if (endExclude > strLength) {
                    endExclude = strLength;
                }

                if (startInclude > endExclude) {
                    return null == str ? null : str.toString();
                } else {
                    char[] chars = new char[strLength];

                    for(int i = 0; i < strLength; ++i) {
                        if (i >= startInclude && i < endExclude) {
                            chars[i] = replacedChar;
                        } else {
                            chars[i] = str.charAt(i);
                        }
                    }
                    return new String(chars);
                }
            }
        }
    }

    /**
     * 删除指定字符
     */
    public static String removeAll(CharSequence str, CharSequence strToRemove) {
        return !isEmpty(str) && !isEmpty(strToRemove) ?
                str.toString().replace(strToRemove, "") :
                (null == str ? null : str.toString());
    }

    public static String removeAny(CharSequence str, CharSequence... strsToRemove) {
        String result = null == str ? null : str.toString();
        if (isNotEmpty(str)) {
            CharSequence[] var3 = strsToRemove;
            int var4 = strsToRemove.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                CharSequence strToRemove = var3[var5];
                result = removeAll(result, strToRemove);
            }
        }
        return result;
    }

    public static String removeAll(CharSequence str, char... chars) {
        if (null != str && !ArrayUtil.isEmpty(chars)) {
            int len = str.length();
            if (0 == len) {
                return null == str ? null : str.toString();
            } else {
                StringBuilder builder = new StringBuilder(len);

                for(int i = 0; i < len; ++i) {
                    char c = str.charAt(i);
                    if (!ArrayUtil.contains(chars, c)) {
                        builder.append(c);
                    }
                }

                return builder.toString();
            }
        } else {
            return null == str ? null : str.toString();
        }
    }

    /**
     * 移除所有换行符
     */
    public static String removeAllLineBreaks(CharSequence str) {
        return removeAll(str, '\r', '\n');
    }

    public static String removeStartAndLowerFirst(CharSequence str, int preLength) {
        if (null == str) {
            return null;
        } else if (str.length() > preLength) {
            char first = Character.toLowerCase(str.charAt(preLength));
            return str.length() > preLength + 1 ? first + str.toString().substring(preLength + 1) : String.valueOf(first);
        } else {
            return str.toString();
        }
    }

    public static String removeStartAndLowerFirst(CharSequence str, CharSequence prefix) {
        return lowerFirst(removeStart(str, prefix));
    }

    public static String removeStart(CharSequence str, CharSequence prefix) {
        if (!isEmpty(str) && !isEmpty(prefix)) {
            String str2 = str.toString();
            return str2.startsWith(prefix.toString()) ? substring(str2, prefix.length()) : str2;
        } else {
            return null == str ? null : str.toString();
        }
    }

    public static String removeStartIgnoreCase(CharSequence str, CharSequence prefix) {
        if (!isEmpty(str) && !isEmpty(prefix)) {
            String str2 = str.toString();
            return str2.toLowerCase().startsWith(prefix.toString().toLowerCase()) ? substring(str2, prefix.length()) : str2;
        } else {
            return null == str ? null : str.toString();
        }
    }

    public static String removeEnd(CharSequence str, CharSequence suffix) {
        if (!isEmpty(str) && !isEmpty(suffix)) {
            String str2 = str.toString();
            return str2.endsWith(suffix.toString()) ? substring(str2, str2.length() - suffix.length()) : str2;
        } else {
            return null == str ? null : str.toString();
        }
    }

    public static String removeEndAndLowerFirst(CharSequence str, CharSequence suffix) {
        return lowerFirst(removeEnd(str, suffix));
    }

    public static String removeEndIgnoreCase(CharSequence str, CharSequence suffix) {
        if (!isEmpty(str) && !isEmpty(suffix)) {
            String str2 = str.toString();
            return str2.toLowerCase().endsWith(suffix.toString().toLowerCase()) ? substring(str2, str2.length() - suffix.length()) : str2;
        } else {
            return null == str ? null : str.toString();
        }
    }

    /**
     * 查询字符总长度
     */
    public static int totalLength(CharSequence... strs) {
        int totalLength = 0;
        CharSequence[] var2 = strs;
        int var3 = strs.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            CharSequence str = var2[var4];
            totalLength += null == str ? 0 : str.length();
        }
        return totalLength;
    }

    /**
     * 生成指定长度字符串，不足位左补充指定字符
     */
    public static String formatStrL(String str, int length, String format) {
        return formatStr(str, length, format, true);
    }

    /**
     * 生成指定长度字符串，不足位右补充指定字符
     */
    public static String formatStrR(String str, int length, String format) {
        return formatStr(str, length, format, false);
    }

    /**
     * 生成指定长度字符串，不足位补充指定字符
     *
     * @param str    原字符串
     * @param length 指定长度
     * @param format 填充字符
     * @param left   填充位置
     */
    public static String formatStr(String str, int length, String format, boolean left) {
        int strLen;
        if (null == str) {
            strLen = 0;
        } else {
            strLen = str.length();
        }

        if (strLen == length) {
            return str;
        } else if (strLen < length) {
            int temp = length - strLen;
            String tem = "";
            for (int i = 0; i < temp; i++) {
                tem = tem + format;
            }
            if (left) {
                return tem + str;
            }
            return str + tem;
        } else {
            return str.substring(0, length);
        }
    }

    /**
     * 转为字符串
     */
    public static String string(Object bytes) {
        return string(bytes, "UTF-8");
    }

    /**
     * 将ByteBuffer转为字符串
     */
    public static String string(Object obj, String charset) {
        if (null == charset) {
            charset = "UTF-8";
        }

        if (null == obj) {
            return null;
        } else if (obj instanceof String) {
            return (String)obj;
        } else if (obj instanceof byte[]) {
            return string((byte[])obj, Charset.forName(charset));
        } else if (obj instanceof Byte[]) {
            return string((Byte[])((Byte[])obj), Charset.forName(charset));
        } else if (obj instanceof ByteBuffer) {
            return string((ByteBuffer)obj, Charset.forName(charset));
        } else {
            return ArrayUtil.isArray(obj) ? arrayToString(obj) : obj.toString();
        }
    }

    public static String string(byte[] data, Charset charset) {
        if (null == data) {
            return null;
        } else {
            return null == charset ? new String(data) : new String(data, charset);
        }
    }

    public static String string(Byte[] data, Charset charset) {
        if (null == data) {
            return null;
        } else {
            byte[] bytes = new byte[data.length];

            for(int i = 0; i < data.length; ++i) {
                Byte dataByte = data[i];
                bytes[i] = null == dataByte ? -1 : dataByte;
            }

            return string(bytes, charset);
        }
    }

    /**
     * 将ByteBuffer转为字符串
     */
    public static String string(ByteBuffer buffer, Charset charset) {
        if (null == charset) {
            charset = Charset.defaultCharset();
        }

        return charset.decode(buffer).toString();
    }

    public static String arrayToString(Object obj) {
        if (null == obj) {
            return null;
        } else if (obj instanceof long[]) {
            return Arrays.toString((long[])((long[])obj));
        } else if (obj instanceof int[]) {
            return Arrays.toString((int[])((int[])obj));
        } else if (obj instanceof short[]) {
            return Arrays.toString((short[])((short[])obj));
        } else if (obj instanceof char[]) {
            return Arrays.toString((char[])((char[])obj));
        } else if (obj instanceof byte[]) {
            return Arrays.toString((byte[])((byte[])obj));
        } else if (obj instanceof boolean[]) {
            return Arrays.toString((boolean[])((boolean[])obj));
        } else if (obj instanceof float[]) {
            return Arrays.toString((float[])((float[])obj));
        } else if (obj instanceof double[]) {
            return Arrays.toString((double[])((double[])obj));
        } else {
            if (ArrayUtil.isArray(obj)) {
                try {
                    return Arrays.deepToString((Object[])((Object[])obj));
                } catch (Exception e) {
                }
            }

            return obj.toString();
        }
    }

    /**
     * 格式化文本,{} 表示占位符<br>
     * <p>如果想输出 {} 使用 \\转义 { 即可
     * 例：<br>
     * 通常使用：format("this is {} for {}", "a", "b") -> this is a for b<br>
     * 转义{}： format("this is \\{} for {}", "a") -> this is {} for a<br>
     * 转义\： format("this is \\{} for {}", "a", "b") -> this is a for b<br>
     * </p>
     *
     * @param template 文本模板
     * @param params   参数值
     * @return 格式化后的文本
     */
    public static String format(String template, Object... params) {
        if (ClassUtil.isEmpty(params) || isEmpty(template)) {
            return template;
        }
        int strPatternLength = template.length();
        // 初始化定义好的长度以获得更好的性能
        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
        int handledPosition = 0;
        int delimIndex;// 占位符所在位置
        for (int argIndex = 0; argIndex < params.length; argIndex++) {
            delimIndex = template.indexOf(EMPTY_JSON, handledPosition);
            if (delimIndex == -1) {
                if (handledPosition == 0) {
                    return template;
                } else { // 字符串模板剩余部分不再包含占位符，加入剩余部分后返回结果
                    sbuf.append(template, handledPosition, strPatternLength);
                    return sbuf.toString();
                }
            } else {
                if (delimIndex > 0 && template.charAt(delimIndex - 1) == C_BACKSLASH) {
                    if (delimIndex > 1 && template.charAt(delimIndex - 2) == C_BACKSLASH) {
                        // 转义符之前还有一个转义符，占位符依旧有效
                        sbuf.append(template, handledPosition, delimIndex - 1);
                        sbuf.append(Convert.toString(params[argIndex]));
                        handledPosition = delimIndex + 2;
                    } else {
                        // 占位符被转义
                        argIndex--;
                        sbuf.append(template, handledPosition, delimIndex - 1);
                        sbuf.append(C_DELIM_START);
                        handledPosition = delimIndex + 1;
                    }
                } else {
                    // 正常占位符
                    sbuf.append(template, handledPosition, delimIndex);
                    sbuf.append(Convert.toString(params[argIndex]));
                    handledPosition = delimIndex + 2;
                }
            }
        }
        // 加入最后一个占位符后所有的字符
        sbuf.append(template, handledPosition, template.length());

        return sbuf.toString();
    }

    /**
     * 根据模板生成最终字符串
     */
    public static String renderData(String source, Map parameter) {
        // 初始化并取得Velocity引擎
        VelocityEngine ve = new VelocityEngine();
        ve.init();
        VelocityContext context = new VelocityContext(parameter);
        // 输出流
        StringWriter writer = new StringWriter();
        ve.evaluate(context, writer, "", source);
        return writer.toString();
    }

    /**
     * 驼峰首字符小写
     */
    public static String uncapitalize(String str) {
        int strLen;
        if (null == str || (strLen = str.length()) == 0) {
            return str;
        }
        return new StrBuilder(strLen).append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
    }

    /**
     * 驼峰式字符串转下划线
     *
     * @param str 转换前的驼峰式参数
     * @return 转换后的带下划线字符串
     */
    public static String toUnderScoreCase(String str) {
        if (null == str) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);

            boolean nextUpperCase = true;

            if (i < (str.length() - 1)) {
                nextUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            if ((i > 0) && Character.isUpperCase(c)) {
                if (!upperCase || !nextUpperCase) {
                    sb.append(SEPARATOR.charAt(0));
                }
                upperCase = true;
            } else {
                upperCase = false;
            }

            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    /**
     * 将字符串转换为驼峰式
     *
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String convertToCamelCase(String name) {
        return convertToCamelCase(name, false);
    }

    /**
     * 将字符串转换为驼峰式
     *
     * @param name       转换前的下划线大写方式命名的字符串
     * @param firstUpper 首字母是否大写
     * @return 转换后的驼峰式命名的字符串
     */
    public static String convertToCamelCase(String name, boolean firstUpper) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (null == name || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains(SEPARATOR)) {
            // 不含下划线，仅将首字母大写
            if (firstUpper)
                return name.substring(0, 1).toUpperCase() + name.substring(1);
            return name;
        }
        // 用下划线将原始字符串分割
        String[] camels = name.split(SEPARATOR);
        for (String camel : camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            result.append(camel.substring(0, 1).toUpperCase());
            result.append(camel.substring(1).toLowerCase());
        }
        String str = result.toString();
        if (!firstUpper) {
            return str.substring(0, 1).toLowerCase() + str.substring(1);
        }
        return str;
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inStringIgnoreCase(String str, String... strs) {
        if (null != str && null != strs) {
            for (String s : strs) {
                if (str.equalsIgnoreCase(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取定长随机字符串
     * <p>由数字和字母组成</p>
     *
     * @param length 位数
     */
    public static String getRandomString(int length) {
        Random rd = new Random();
        String n = "";
        int rdGet;
        do {
            if (rd.nextInt() % 2 == 1) {
                // 产生48到57的随机数(0-9的鍵位值)
                rdGet = Math.abs(rd.nextInt()) % 10 + 48;
            } else {
                // 产生97到122的随机数(a-z的鍵位值)
                rdGet = Math.abs(rd.nextInt()) % 26 + 97;
            }
            char num1 = (char) rdGet;
            String dd = Character.toString(num1);
            n += dd;

        } while (n.length() < length);
        return n;
    }

    /**
     * 获取定长随机数字
     * <p>由数字组成</p>
     *
     * @param length 位数
     */
    public static String getRandomNumber(int length) {
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(NUMBER_CHAR.charAt(random.nextInt(NUMBER_CHAR.length())));
        }
        return sb.toString();
    }

    /**
     * 清除特殊字符
     * <p>
     * 特殊字符包括：
     * `~!@#$%^&*()+=|{}':;',//[//].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？
     * </p>
     */
    public static String filter(String str) {
        if (str == null)
            return "";
        String regEx = "[`~!@#$%^&*()+=|{}':;',//[//].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.replaceAll("").trim();
    }

    /**
     * 去除筛选字符
     *
     * @param data   被筛选字符串
     * @param filter 筛选字段关键字
     */
    public static String formatData(String data, List<String> filter) {
        if (null == data) {
            return data;
        }
        data = data.toLowerCase();
        for (int i = 0; i < filter.size(); i++) {
            data = data.replaceAll((filter.get(i).toLowerCase()), "");
        }
        data = data.replaceAll(" ", "");
        return data;
    }

    /**
     * 去除字符串中所有空格
     */
    public static String trimAll(Object data) {
        if (null != data) {
            return data.toString().replaceAll(" ", "");
        }
        return null;
    }

    /**
     * 字符串格式化成sql参数
     * <p>传入 a,b,c 格式化=> 'a','b','c'</p>
     *
     * @param sSource 原始参数
     * @return sql使用参数
     */
    public static String convert2Sql(String sSource) {
        if (isEmpty(sSource))
            sSource = "''";
        else {
            sSource = sSource.replaceAll("，", ",")
                    .replaceAll(",", "','");
            sSource = "'" + sSource + "'";
        }
        return sSource;
    }

    /**
     * 字符串数组格式化成sql参数：
     * <p>传入字符串数组格式化后 'a','b','c'
     *
     * @param sSource 原始参数
     * @return sql使用参数
     */
    public static String convert2Sql(String[] sSource) {
        String res;
        if (null == sSource || sSource.length == 0)
            res = "''";
        else {
            StringBuffer str_buf = new StringBuffer();
            for (String str : sSource) {
                str_buf.append("'" + str + "',");
            }
            if (str_buf.length() > 0) {
                str_buf.setLength(str_buf.length() - 1);
            }
            res = str_buf.toString();
        }
        return res;
    }

    /**
     * 字符串数组格式化成sql参数
     *
     * @param sSource 原始参数
     * @return sql使用参数
     */
    public static String convert2Sql(Object[] sSource) {
        String res;
        if (null == sSource || sSource.length == 0)
            res = "''";
        else {
            StringBuffer str_buf = new StringBuffer();
            for (Object str : sSource) {
                if (str instanceof String) {
                    str_buf.append("'" + str + "',");
                } else {
                    str_buf.append(str + ",");
                }
            }
            if (str_buf.length() > 0) {
                str_buf.setLength(str_buf.length() - 1);
            }
            res = str_buf.toString();
        }
        return res;
    }

    /**
     * 根据当前版本号，获取指定位数版本号
     * <p> 例如：两位版本号 01、02、...10...99</p>
     *
     * @param prevVersion 当前版本号
     * @param bit         版本号位数
     * @return 两位版本号
     */
    public static String getBitVersion(String prevVersion, int bit) {
        String defaultStr = "0";
        if (isEmpty(prevVersion)) {
            for (; bit > 2; bit--) {
                defaultStr += defaultStr;
            }
            defaultStr += "1";
            return defaultStr;
        } else {
            String preStr;
            if (prevVersion.indexOf(".") != -1) {
                preStr = prevVersion.substring(0, prevVersion.indexOf("."));
            } else {
                preStr = prevVersion;
            }
            return String.format("%" + bit + "s", preStr).replace(' ', '0');
        }
    }

    /**
     * 按字节截取中文字符串
     *
     * @param org   原始字符串
     * @param count 截取位数
     */
    public static String substringChinese(String org, int count) {
        // 原始字符不为null，也不是空字符串
        if (isNotEmpty(org)) {
            // 将原始字符串转换为GBK编码格式
            org = new String(org.getBytes(), StandardCharsets.UTF_8);
            // 要截取的字节数大于0，且小于原始字符串的字节数
            if (count > 0 && count < org.getBytes(StandardCharsets.UTF_8).length) {
                StringBuffer buff = new StringBuffer();
                char c;
                for (int i = 0; i < count; i++) {
                    c = org.charAt(i);
                    buff.append(c);
                    if (isChinese(c)) {
                        // 遇到中文汉字，截取字节总数减2
                        count -= 2;
                    }
                }
                return buff.toString();
            }
        }
        return org;
    }

    /**
     * 根据Unicode编码判断是否中文汉字和符号
     */
    private static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION;
    }

    /**
     * 判断是否事Emoji字符
     */
    public static boolean isEmoji(char c) {
        return c != 0 && c != '\t' && c != '\n' && c != '\r' && (c < ' ' || c > '\ud7ff') && (c < '\ue000' || c > '�') && (c < 1048576 || c > 1114111);
    }

    /**
     * Clob转成字符串
     */
    public static String ClobToString(Clob clob) {
        Reader is = null;
        try {
            is = clob.getCharacterStream();
        } catch (SQLException e) {
            log.error("读取Clob异常：{}", e.getMessage());
            return null;
        }

        BufferedReader br = new BufferedReader(is);
        String s = null;
        StringBuffer sb = new StringBuffer();
        do {
            try {
                s = br.readLine();
                if (null != s) {
                    sb.append(s);
                }
            } catch (IOException e) {
                log.error("读取Clob异常：{}", e.getMessage());
            }
        } while (null != s);
        return sb.toString();
    }

    /**
     * 判断两个字符串数组内容是否一样
     * <p>如果两个数组有一个为null则返回false</p>
     *
     * @param arr1 数组1
     * @param arr2 数组2
     * @param type 0:两个数组完全一致 1:两个数组只需一个匹配
     * @return
     */
    public static boolean isEqual(String[] arr1, String[] arr2, int type) {
        if (null == arr1 || null == arr2) {
            return false;
        }
        if (arr1.length != arr2.length && type == 0) {
            return false;
        }
        int i = 0;
        jump:
        for (String arr1_tmp : arr1) {
            for (String arr2_tmp : arr2) {
                if (arr1_tmp.trim().equals(arr2_tmp.trim())) {
                    if (type == 1) {
                        i = arr1.length;
                        break jump;
                    }
                    i++;
                    break;
                }
            }
        }
        return i == arr1.length;
    }

    /**
     * 查找指定字符串在数组中的位置,不存在返回-1
     *
     * @param str 目标字符串
     * @param arr 目标数组
     * @return 字符串在数组中的位置
     */
    public static int getIndexOfString(String str, String[] arr) {
        if (null == arr || isEmpty(str)) {
            return -1;
        }
        for (int i = 0; i < arr.length; i++) {
            if (str.equals(arr[i])) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 判断网页传递的参数是否为undefined
     */
    public static boolean isEmptyParameter(String param) {
        return !(StringUtil.isNotEmpty(param)
                && !"none".equalsIgnoreCase(param)
                && !"null".equalsIgnoreCase(param)
                && !"undefined".equalsIgnoreCase(param));
    }

    /**
     * 获取标签之间内容
     */
    public static String extractMessage(String message, char extractL, char extractR) {
        List<String> list = new ArrayList<>();
        int start = 0;
        int startFlag = 0;
        int endFlag = 0;
        for (int i = 0; i < message.length(); i++) {
            if (message.charAt(i) == extractL) {
                startFlag++;
                if (startFlag == endFlag + 1) {
                    start = i;
                }
            } else if (message.charAt(i) == extractR) {
                endFlag++;
                if (endFlag == startFlag) {
                    list.add(message.substring(start + 1, i));
                }
            }
        }
        if (startFlag == 0) {
            return message;
        }
        return list.get(list.size() - 1);
    }

    /**
     * 获取标签之间内容
     */
    public static String extractMessage(String message, String extractL, String extractR) {
        try {
            int start = message.indexOf(extractL) + 1;
            String rightStr = message.substring(start);
            if (rightStr.indexOf(extractR) != -1) {
                return rightStr.substring(0, rightStr.indexOf(extractR));
            }
            return rightStr;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 提取指定占位符中的内容
     */
    public static List<String> extractMessageByRegular(String message, String pattern) {
        List<String> list = new ArrayList<>();
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(message);
        while (m.find()) {
            list.add(m.group().substring(1, m.group().length() - 1));
        }
        return list;
    }

    public static boolean equalsWithEmpty(final CharSequence cs1, final CharSequence cs2) {
        if (null == cs1 && null == cs2) {
            return true;
        }
        return equals(cs1, cs2);
    }

    public static boolean isNumber(String string) {
        return Pattern.compile("^(\\-|\\+)?\\d+(\\.\\d+)?$", Pattern.DOTALL).matcher(string).matches();
    }

    /**
     * 提取数字
     */
    public static double patternNumber(String string) {
        String regEx = "[^-^0-9.]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(string);
        return Convert.toDouble(m.replaceAll("").trim(), 0.0);
    }

    /**
     * 查找字符串所在索引
     *
     * @param list
     * @param key
     * @param fuzzy 是否模糊匹配
     */
    public static int findIndexOfList(String[] list, String key, boolean fuzzy) {
        for (int i = 0; i < list.length; i++) {
            if (fuzzy) {
                if (key.indexOf(list[i]) > -1) {
                    return i;
                }
            } else {
                if (key.equals(list[i])) {
                    return i;
                }
            }
        }
        return 0;
    }

    public static String unescapeJava(String input) {
        return UNESCAPE_JAVA.translate(input);
    }

    public static String unescapeHtml4(String input) {
        return UNESCAPE_HTML4.translate(input);
    }

    /**
     * 计算SHA-1散列值
     */
    public static byte[] sha1(byte[] bytes) {
        final MessageDigest digest = DigestUtil.sha1();
        digest.update(bytes);
        return digest.digest();
    }

    /**
     * 将字节数组转为十六进制字符串
     */
    public static String hex(byte[] bytes) {
        if (null == bytes) {
            return null;
        }
        String hex;
        final StringBuilder builder = new StringBuilder();
        for (int index = 0; index < bytes.length; index++) {
            hex = Integer.toHexString(bytes[index] & 0xFF);
            if (hex.length() < 2) {
                builder.append(0);
            }
            builder.append(hex);
        }
        return builder.toString().toLowerCase();
    }

    /**
     * 将十六进制字符串转为字节数组
     */
    public static byte[] unhex(String content) {
        if (null == content) {
            return null;
        }
        byte[] result;
        int length = content.length();
        if (length % 2 == 1) { // 奇数
            length++;
            result = new byte[(length / 2)];
            content = "0" + content;
        } else { // 偶数
            result = new byte[(length / 2)];
        }
        int jndex = 0;
        for (int index = 0; index < length; index += 2) {
            result[jndex] = (byte) Integer.parseInt(content.substring(index, index + 2), 16);
            jndex++;
        }
        return result;
    }

    /**
     * 判断是否匹配正则表达式
     *
     * @param value      字符串
     * @param regex      正则表达式
     * @param ignoreCase 是否忽略大小写
     */
    public static boolean regex(String value, String regex, boolean ignoreCase) {
        if (null == value || null == regex) {
            return false;
        }
        Pattern pattern;
        if (ignoreCase) {
            pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        } else {
            pattern = Pattern.compile(regex);
        }
        final Matcher matcher = pattern.matcher(value);
        return matcher.matches();
    }

    public static String substring(String string, CharSequence separator, boolean isLastSeparator) {
        if (isEmpty(string)) {
            return null == string ? null : "";
        } else if (null == separator) {
            return "";
        } else {
            String str = string;
            String sep = separator.toString();
            int pos = isLastSeparator ? str.lastIndexOf(sep) : str.indexOf(sep);
            return -1 != pos && string.length() - 1 != pos ? str.substring(pos + separator.length()) : "";
        }
    }

    /**
     * 将对象转为字符串
     * <p>默认编码：UTF-8</p>
     */
    public static String getString(Object object) {
        return getStringCharset(object, null);
    }

    /**
     * 将对象转为字符串
     *
     * @param object   对象
     * @param encoding 编码
     */
    public static String getStringCharset(Object object, String encoding) {
        if (null == object) {
            return null;
        }
        if (object instanceof byte[]) {
            final byte[] bytes = (byte[]) object;
            if (null != encoding) {
                try {
                    return new String(bytes, encoding);
                } catch (UnsupportedEncodingException e) {
                    log.error("字符编码异常：{}", encoding, e);
                }
            }
            return new String(bytes);
        } else {
            return object.toString();
        }
    }

    /**
     * 数据脱敏
     *
     * @param data
     * @return
     */
    public static String mask(String data) {
        if (isNotEmpty(data) && data.length() > 0) {
            return mask(data, 0, 0);
        }
        return data;
    }

    /**
     * 数据脱敏
     *
     * @param data
     * @param left  左显示个数
     * @param right 右显示个数
     * @return
     */
    public static String mask(String data, int left, int right) {
        if (isNotEmpty(data) && data.length() > 0) {
            return left(data, left)
                    .concat(removeStart(
                            leftPad(right(data, right), length(data), "*"),
                            leftPad("", left, "*")));
        }
        return data;
    }
}
